package de.sendorian.util.io;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLConnection;

import javax.imageio.ImageIO;

import org.apache.log4j.Logger;
import org.htmlparser.http.ConnectionManager;
import org.htmlparser.util.ParserException;


public class FileReader {

    private static final Logger logger = Logger.getLogger(FileReader.class.getName());

    private ConnectionManager connectionManager = new ConnectionManager();


    public byte[] getFile(String url) throws IOException {
        return getFile(getInputStream(url));
    }


    public byte[] getFile(InputStream in) throws IOException {
        long start = System.currentTimeMillis();
        byte[] out = new byte[0];

        try {
            in = new BufferedInputStream(in);
            // read 64 kb at once
            int bufLen = 64 * 1024;
            byte[] buf = new byte[bufLen];
            byte[] tmp = null;
            int len = 0;
            while ((len = in.read(buf, 0, bufLen)) != -1) {
                // extend array
                tmp = new byte[out.length + len];
                // copy data
                System.arraycopy(out, 0, tmp, 0, out.length);
                System.arraycopy(buf, 0, tmp, out.length, len);
                out = tmp;
                tmp = null;
            }
            logger.debug("   Time for Saving file: " + (System.currentTimeMillis() - start) + " [ms]");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
        }

        return out;
    }


    /**
     * Directly saves a file specified by a given URL to a file whithout storing
     * it in memory.
     */
    public boolean save(String url, String dir, String fileName) throws IOException {
        File file = new File(dir, fileName);
        if (file.exists()) {
            logger.info("The file \"" + dir + java.io.File.separator + fileName + "\" already exists. Skipping.");
            return false;
        }
        return save(getInputStream(url), file, dir);
    }


    /**
     * Directly saves a file specified by a given URL to a file whithout storing
     * it in memory.
     */
    public boolean save(InputStream in, String dir, String fileName) throws IOException {
        File file = new File(dir, fileName);
        if (file.exists()) {
            logger.info("The file \"" + dir + java.io.File.separator + fileName + "\" already exists. Skipping.");
            return false;
        }
        return save(in, file, dir);
    }


    private boolean save(InputStream in, File file, String dir) throws IOException {
        new FileWriter().createDir(dir);
        file.createNewFile();

        OutputStream out = new BufferedOutputStream(new FileOutputStream(file), 64 * 1024);
        // read 64 kb at once
        in = new BufferedInputStream(in, 64 * 1024);

        try {
            int readByte = -1;
            while ((readByte = in.read()) != -1) {
                out.write(readByte);
            }
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                }
            }
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (Exception e) {
                }
            }
        }
        return true;
    }


    public BufferedImage getImage(String url) throws IOException {
        InputStream in = getInputStream(url);
        return ImageIO.read(in);
    }


    private InputStream getInputStream(String url) throws IOException {
        if (url.startsWith("file://")) {
            File file = new File(url.substring("file://".length()));
            return new FileInputStream(file);
        } else {
            URLConnection connection = null;
            try {
                connection = connectionManager.openConnection(url);
            } catch (ParserException e) {
                String message = "Could not open connection to '" + url + "'";
                logger.error(message);
                throw new IOException(message);
            }
    
            connection.connect();
            return connection.getInputStream();
        }
    }

}
